package expressions;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import tester.Example;
import tester.TestMethod;
import tester.Tester;
import tester.cobertura.Instrument;

/**
 * Title : BE :  Boolean Expression
 * 
 * Javadoc Online at : http://www.ccs.neu.edu/home/ada2358/Doc/Satisfiability/index.html
 * @author Adam Blackwell
 * @version 1.0
 * @since April 2nd 2009
 */
@Example @Instrument
public abstract class BE {
  
  /**
   * @return
   */
  public Boolean isTotal() {
    int vars = this.countVariables();
    HashMap<String, Boolean> values = this.getVariables();
    boolean answer = true;
    for (int i = 0; i <= Math.pow(2, vars); i++) {
      Iterator<String> it = values.keySet().iterator();
      for (int j = 0; j <= vars; j++) {
        if(j % Math.pow(2, (j)) < Math.pow(2, (j))) {
          values.put(it.next(), false);
        } else{
          values.put(it.next(), true);
        }
      }
      answer = answer && this.Evaluate(values);
    }
    return answer;
  }
  
//  /**
//   * @param vars
//   * @return
//   */
//  private Boolean isTotalAcc(int vars) {
//    // Gives up on recursive style...
//    // TODO Auto-generated method stub
//    // So I want to go through and && every possible permutation of the vars list...
//    // I'm stuck...
//    return false;
//  }
  
  /**
   * @return
   */
  public Boolean isSatisfiable() {
    int vars = this.countVariables();
    return this.isSatisfiableAcc(vars); 
  }
  
  /**
   * @param vars
   * @return
   */
  private Boolean isSatisfiableAcc(int vars) {
    // TODO Auto-generated method stub
    // So I want to go through and || every possible permutation of the vars list...
    // I'm stuck...
    return false;
  }

  /**
   * @return
   */
  public Boolean Evaluate(HashMap<String, Boolean> vars) {
    return this.accept(new BEEvalVisitor(vars));
  }
  
  /**
   * @return
   */
  public Boolean Evaluate() {
    return this.accept(new BEEvalVisitor());
  }
  
  /**
   * @param visit
   * @return
   */
  public int countVariables() {
    return getVariables().size();
  }
  
  /**
   * @return
   */
  public HashMap<String, Boolean> getVariables() {
    return new HashMap<String, Boolean>(this.accept(new BEVarVisitor()));
  }
  
  /**
   * @param <R>
   * @param visit
   * @return
   */
  public abstract <R> R accept(BEVisitor<R> visit);
  
  /* (non-Javadoc)
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public abstract boolean equals(Object obj);
  
  /* (non-Javadoc)
   * @see java.lang.Object#hashCode()
   */
  public abstract int hashCode();
  
  /* *************** *
   * Testing :       *
   * *************** */
   
  @TestMethod
  public void tests(Tester t) {
    BE be1 = new And(new Var("x", true), new Var("y", false));
    BE be2 = new And(new Var("x", true), 
                      new Or(new Not(new Var("z", true)),
                             new Var("y", false)));
    BE be3 = new And(new Var("x", true), 
                     new Not(new Var("z", false)));
    t.checkExpect(be1.isTotal(), false);
    t.checkExpect(be2.isTotal(), false);
    t.checkExpect(be3.isTotal(), true);
  }
}
